package hooks

import (
	"bytes"
	"context"
	"io"
	"testing"
	"time"

	"atomgit.com/atomgit_dev/git-hooks/pkg/config"
	"atomgit.com/atomgit_dev/git-hooks/pkg/streamio"
	pb "atomgit.com/atomgit_dev/satellite-proto/go"
	"github.com/stretchr/testify/require"

	log "atomgit.com/atomgit_dev/alog/alogcore"
)

const largeRepoMessage = "The current repository is large, it is recommended to use 'partial clone' to\ndownload files on demand, or use 'Large File Storage'(LFS) to efficiently\nmanage binary files and enhance the experience of cloning large repositories.\nIf you just need to build, it is recommended to use shallow clones.\nLearn more: https://help.aliyun.com/document_detail/324168.html\n"

func (s *mockServer) PreSendPackHook(in *pb.PreSendPackHookRequest, stream pb.HookService_PreSendPackHookServer) error {
	log.Info(stream.Context(), "PreSendPackHook")

	have := in.GetHave()
	filter := in.GetFilter()
	depth := in.GetDepth()

	resp := &pb.PreSendPackHookResponse{
		ExitStatus: &pb.ExitStatus{
			Value: 0,
		},
	}

	if have != 0 || filter != 0 || depth != 0 {
		return stream.Send(resp)
	}

	stdout := streamio.NewWriter(func(p []byte) error {
		resp.Stdout = p
		return stream.Send(resp)
	})
	buf := bytes.NewBufferString(largeRepoMessage)
	_, err := io.Copy(stdout, io.Reader(buf))
	return err
}

func TestPreSendPack(t *testing.T) {
	server, _ := startTestServices(t)
	defer server.Stop()

	// must set env: AGIT_PROTO_REPOSITORY
	addPbRepositoryToEnv(&pb.Repository{
		GlRepositoryId: 88084,
	})

	// grpc server listen port
	config.Load(config.Config{
		ServerEndPoint:    "localhost",
		ServerPort:        58089,
		PreReceiveTimeout: time.Second * 5,
	})

	tcs := []struct {
		name         string
		opt          config.PreSendPackOption
		expectStdout string
		expectCode   int
	}{
		{
			name:         "the clone case",
			expectCode:   0,
			expectStdout: largeRepoMessage,
		},
		{
			name: "the partial clone case",
			opt: config.PreSendPackOption{
				Have: 1,
			},
			expectCode: 0,
		},
	}

	for _, ts := range tcs {
		t.Run(ts.name, func(t *testing.T) {
			// read stdout
			buf := bytes.NewBuffer([]byte{})
			returnCode, err := preSendPack(context.Background(), ts.opt, buf, nil)
			if err != nil {
				t.Fatalf("pre-send-pack execute err: %v", err)
			}

			require.Equal(t, returnCode, ts.expectCode, "return code should be 0")
			require.EqualValues(t, ts.expectStdout, buf.String(), "return message not be expect values")
		})
	}
}
